﻿using System.Collections.Generic;
using System.ComponentModel;
using System.Linq.Expressions;
using System;

namespace PersonaLibrary.Search
{
    public class BaseSearchProperty : INotifyPropertyChanged
    {
        private object _sValue;
        private List<string> _unaryOperators;
        private string _selectedUnaryOperator;
        private string _propertyName;

        public object Value
        {
            set
            {
                _sValue = value;
                RisePropertyChanged("Value");
                onValueChanged();
            }
            get
            {
                return _sValue;
            }
        }

        public List<string> UnaryOperators
        {
            get
            {
				if (_unaryOperators == null)
				{
					_unaryOperators = CreateUnaryOperators();
					if (_unaryOperators != null && _unaryOperators.Count > 0)
						SelectedUnaryOperator = _unaryOperators[0];
				}
            	return _unaryOperators;
            }
        }

        public string SelectedUnaryOperator
        {
            set
            {
                _selectedUnaryOperator = value;
                RisePropertyChanged("SelectedUnaryOperator");
            }
            get
            {
                return _selectedUnaryOperator;
            }
        }

        public string PropertyName
        {
            set
            {
                _propertyName = value;
                OnPropertyNameChanged();
            }
            get { return _propertyName; }
        }

        public override string ToString()
        {
            return DisplayName;
        }

        public string DisplayName { set; get; }

        public BaseSearchProperty(ParameterExpression parametr)
        {
            Parametr = parametr;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public virtual Expression CreateUnary()
        {
            Expression result = null;

            switch (_selectedUnaryOperator)
            {
                case "=":
                    result = Property.NotNullTesting(Expression.Equal(Property, Constant));
                    break;
                case "!=":
                    result = Property.NotNullTesting(Expression.NotEqual(Property, Constant));
                    break;
            }

            return result;
        }

        protected ParameterExpression Parametr { private set; get; }

        protected MemberExpression Property { private set; get; }

        protected ConstantExpression Constant { set; get; }

        protected virtual List<string> CreateUnaryOperators()
        {
            return new List<string> { "=", "!=", };
        }

        protected void RisePropertyChanged(string name)
        {
            if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        private void OnPropertyNameChanged()
        {
			RisePropertyChanged("PropertyName");
            MemberExpression property = null;
            foreach (var propName in PropertyName.Split(".".ToCharArray()))
            {
                if (property == null)
                {
                    property = Expression.Property(Parametr, propName);
                }
                else
                    property = Expression.Property(property, propName);
            }
            Property = property;
        }

        private void onValueChanged()
        {
            Constant = Expression.Constant(Value);
        }
    }

    internal static class PropertyHelper
    {
        public static Expression NotNullTesting(this MemberExpression property, Expression exp)
        {
            Expression result = null;

            result = Expression.Condition(Expression.NotEqual(property, Expression.Constant(null)), exp, Expression.Constant(false));
            MemberExpression tmp = property.Expression as MemberExpression;

            while (tmp != null)
            {
                result = Expression.Condition(Expression.NotEqual(tmp, Expression.Constant(null)), result, Expression.Constant(false));
                tmp = tmp.Expression as MemberExpression;
            }

            return result;
        }
    }
}
